import Flutter
import UIKit
import Alamofire

#if DEBUG
    func DLog(_ items: Any..., separator: String = " ", terminator: String = "\n"){
        print(items,separator: separator,terminator: terminator);
    }
#else
    func DLog(_ items: Any..., separator: String = " ", terminator: String = "\n"){}
#endif

public class SwiftNativeDioAdapterPlugin: NSObject, FlutterPlugin {
  public static func register(with registrar: FlutterPluginRegistrar) {
    let channel = FlutterMethodChannel(name: "native_dio_adapter", binaryMessenger: registrar.messenger())
    let instance = SwiftNativeDioAdapterPlugin()
    registrar.addMethodCallDelegate(instance, channel: channel)
  }

  public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
    //result("iOS " + UIDevice.current.systemVersion)
    switch call.method {
        case "sendRequest":
        sendRequest(call.arguments) { response in
            result(response.toMap())
        }
        default:
          result(FlutterMethodNotImplemented)
      }
  }
}

private extension SwiftNativeDioAdapterPlugin{
    
   func sendRequest(_ arguments: Any?,finish:@escaping (AFRequestResult) -> Void) {
      do {
          let args = arguments as! [String: Any?]
          let option = NativeRequestOptions.fromMap(args)
          if(option.url.isEmpty)
          {
              let result = AFRequestResult(response: nil, failure:"DioRequestOptions url 为空" )
              finish(result)
              return
          }
          let request = isUploadRequest(option) ? getUploadRequst(option) : getDefaultRequest(option)
          if(request == nil)
          {
              let result = AFRequestResult(response: nil, failure:"Create request filure")
              finish(result)
          }
          waitResult(request!,finish: finish)
        } catch {
                let result = AFRequestResult(response: nil, failure:error.localizedDescription )
                finish(result)
        }
    }
    
    func isUploadRequest(_ option: NativeRequestOptions) -> Bool {
        let contentType = option.headers?.value(for: "Content-Type")
        let multipartForm = contentType?.contains("multipart/form-data") ?? false
        return multipartForm;
    }
    

    
    func getDefaultRequest(_ option: NativeRequestOptions) -> DataRequest?{
        
        return  AF.request(option.url,
                           method: option.method,
                           parameters: option.parameters,
                           encoding: option.encoding,
                           headers: option.headers,
                           requestModifier: { $0.timeoutInterval = TimeInterval(option.timeout)}
      //                     requestModifier: { urlRequest in
      //              urlRequest.timeoutInterval = 15
      //          }
        );
    }
    
    func getUploadRequst(_ option: NativeRequestOptions) -> DataRequest?{
        guard let arg = option.parameters as? [String:Array<[String:String]>] else {
            return nil
        }
        let files = NativeMultipartFile.fromMap(arg)
        return AF.upload(
                multipartFormData: { multipartFormData in
                    for item in files{
                        for element in item.value{
                            multipartFormData.append(element.data, withName: item.key,fileName: element.fileName,mimeType: element.mediaType)
                        }
                    }
                 },
                  to: option.url,
                   usingThreshold:MultipartFormData.encodingMemoryThreshold,
                   method: option.method,
                   headers: option.headers,
                   requestModifier: { $0.timeoutInterval = TimeInterval(option.timeout)}
        )
    }
    
    func waitResult(_ request: DataRequest,finish: @escaping (AFRequestResult) -> Void) {
        let redirector = Redirector(behavior: .doNotFollow)
        request.redirect(using: redirector)
        //.validate()
        .response { response in
//            DLog("AF >>>>>>>>> Request >>>>Http Body:\(String(describing: response.request?.httpBody))",separator: "\n")
            DLog("AF >>>>>>>>> Response:\(String(describing: response.request?.url))，>>>>Status:\(String(describing: response.response?.statusCode)),>>>>Duration:\(String(describing:response.metrics?.taskInterval.duration))",separator: "\n")
            if(response.error != nil){
                let result = AFRequestResult(response: nil, failure:response.error!.localizedDescription )
                finish(result)
                return
            }
            var nativeResponse = NativeResponse(data: response.data)
            nativeResponse.headers = response.response?.headers.dictionary
            nativeResponse.statusCode = response.response?.statusCode
            let result = AFRequestResult(response: nativeResponse)
            finish(result)
        }
    }
    
}
